#ifndef NETWORKCONTROL_H_
#define NETWORKCONTROL_H_
/*********************************************************/
#include "misc/MultiNet.h"
#include "misc/UDPNet.h"
#include "server/net/sMsg.h"
#include "server/multiProtocol/multiMsg.h"
#include "misc/Timer.h"

#include <Poco/Runnable.h>
#include <Poco/Thread.h>
#include <Poco/Mutex.h>
#include <Poco/Net/NetworkInterface.h>
#include <queue>
#include <string>
#include <map>

#define NET_TRAFFIC_EVENT	"NETWORK_TRAFFIC"
#define JOB_AVAILABLE_EVENT	"JOB_AVAILABLE"
#define MULTICAST_PROTOCOL_TIMER 1000
#define MULTICAST_RING_CREATE_PAUSE 5000000		// How long do we wait for responses before continuing creating a ring ( in microseconds )
#define MULTICAST_RING_KEEPALIVE 10000000		// How frequent are we sending keep alive multiRing messages
#define MAX_HASH_VALUE		"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"	// Maximum hash value for a 160 bit key

#define ACKMAP_ std::map<std::string, std::map<unsigned long, std::string> >
/*********************************************************/
struct Node {
	std::string	hash;		// Hash value for the current ring node
	std::string	predecessor;	// Predecessor ip address
	std::string	successor;	// Successor ip address
	std::string	addr;		// Node address ( unicast )
};
/*********************************************************/
/** This is the heart of the middleware layer, it will control all the network classes:
 ** MultiNet, UDPNet and TCPNet. It converts raw message strings coming from the network 
 ** to a workable job object ( serialization/deserialization ). The class also provides 
 ** a filter to seperate valid packets from junk packets possibly coming from other processes
 ** and/or systems that are having Byzantine errors **/
class NetworkControl : public Poco::Runnable
{
private:
	// Friend declarations
	friend class MultiDiscovery;
	friend class MultiUpdate;
	friend class MultiLeave;
	friend class MultiJoin;
	friend class MultiRing;
	friend class MultiMsg;
	friend class sMsg;
	friend class sAnnounce;
	friend class sDiscovery;
	friend class sAck;
	friend class sGet;
	friend class sPut;
	friend class sExecute;
	friend class sData;
	friend class sRegister;
	friend class sUnRegister;
	friend class sKeepAlive;

	// General data for Middleware control & subclasses
	static NetworkControl&		pInstance;		// Pointer to the single available instance of the class
	static Poco::Mutex*		mutex;			// mutual exclusion object
	Poco::Net::SocketAddress	nsAddr;			// Nameserver unicast address
	std::queue<sMsg*>		jobQueue;		// Queue holding jobs that are ready for processing
	unsigned long			counter;		// ID counter used to produce unique id's for the network packets
	Poco::Thread			lThread;		// Local thread handle
	Poco::Timestamp			tPred;			// Last instant of time we had contact with our predecessor
	Poco::Timestamp			tSucc;			// Last instant of time we had contact with our successor in the ring
	Poco::Timestamp			keepalive;		// Last instant of time we checked our keepalive timers
	ACKMAP_				ackmap;			// The waiting for acknowledgement map
	MultiNet*			multicast;		// The multicasting network class
	UDPNet*				unicast;		// The unicast network class ( at this point only udp is supported )
	Timer*				mTimer;			// Multicast code timer
	bool				halt;			// does the local thread need to stop?		

	// State data about the current ring & ring control variables
	Poco::Timestamp			startTime;		// Registers when we were asked for a ring creation
	std::vector<Node>		nodes;			// Nodes taking part of the ring
	Node				node;			// Data about us ( as a part of a ring )
	bool				ringChange;		// Local changes were made to the ring
	bool				ringInit;		// Are we still in the ring initialization/join phase?

	// Methods
	void run();					// Thread entry point for the class
	void runMulticastProtocol();			// Run the multicast protocol code
	void uploadFiles(const std::string& target);	// Upload all files to the ring when we leave the ring
	void runKeepAlive();				// Check if we need to send any keep alive messages
	void detectNameServer();			// Joins the nameserver group and searches for the nameserver unicast address
	unsigned long getID();				// Returns a unique id for a job

protected:
	// Construction & Destruction
	NetworkControl();				// Prohibit use of constructor ( singleton! )
	NetworkControl(const NetworkControl&);		// Same for the copy constructor... 
public:
	// Singleton design Methods
	static NetworkControl& Instance();		// Instance retrieval method

	// Middleware Control Methods
	std::string getRingInformation() const;		// Returns all known information about all rings in a structured string
	std::string getLocalAddress() const;		// Returns the unicast network address currently in use
	std::string getLocalHash() const;		// Returns the local hash used in the ring
	std::string getPredecessor() const;		// Returns the predecessor address
	std::string getSuccessor() const;		// Returns the successor address
	std::string getSuccessorHash() const;		// Returns the hash key of the successor
	std::string getPredecessorHash() const;		// Returns the hash key of the predecessor
	bool getRingActive() const;			// Returns true if we are part of a ring, false otherwise
	bool getRingUpdate() const;			// Returns true if the ring was altered in our area
	void setRingUpdate(bool);			// Used to set the ring status in the internal state

	// Network methods
	void send(const sMsg*);				// Send a message to the stored response address
	void sendTo(const sMsg*, const std::string&);	// Send a message to a specified address
	void broadcast(const MultiMsg*);		// Broadcast a message on the multicast group
	bool waitForAck(const std::string&, const unsigned long&);		// Wait for an ack of a specific message

	// Job retrieval methods
	bool available() const;				// Returns true is a job is waiting otherwise false
	sMsg* pop();					// Pop a job from the queue and return it

	// Class Control Methods
	void start();					// Stop the internal thread
	void stop();					// Start the internal thread

	// Information retrieval methods
	static std::string getNetworkInterface();	// Returns a useable network interface

	// Construction & Destruction
	virtual ~NetworkControl();			// Destructor
};
/*********************************************************/
#endif //NETWORKCONTROL_H_
